package com.csproj.dispatch.service;

import com.csproj.basic.domain.*;
import com.csproj.basic.repository.*;
import com.csproj.basic.service.dto.ElectronicLockMessageDTO;
import com.csproj.basic.service.mapper.ElectronicLockMessageMapper;
import com.csproj.dispatch.BaseService;
import com.csproj.dispatch.domain.Dispatch;
import com.csproj.dispatch.domain.Logistics;
import com.csproj.dispatch.domain.ProductInfo;
import com.csproj.dispatch.domain.WarnInfo;
import com.csproj.dispatch.repository.*;
import com.csproj.dispatch.service.dto.DispatchDTO;
import com.csproj.dispatch.service.mapper.DispatchMapper;
import com.csproj.dispatch.util.PointSurface;
import com.csproj.dispatch.util.entity.DispatchRouteParam;
import com.csproj.dispatch.util.entity.HistoryPosition;
import com.csproj.dispatch.util.entity.HistoryPositionDetail;
import com.csproj.siiat.base.common.dto.BaseDTO;
import com.csproj.siiat.base.common.repository.PageableTools;
import com.csproj.siiat.base.common.repository.SortDto;
import com.csproj.siiat.config.Languagesproperties;
import com.csproj.siiat.security.CurrentUser;
import com.csproj.siiat.security.SecurityUtils;
import com.csproj.system.domain.Language;
import com.csproj.system.repository.LanguageRepository;
import com.csproj.system.service.UserInfoService;
import org.apache.commons.lang3.StringUtils;
import com.csproj.dispatch.util.ContainerStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.*;
import javax.persistence.criteria.Path;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.time.ZonedDateTime;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Service Implementation for managing Dispatch.
 */
@Service
@Transactional
public class DispatchService extends BaseService<DispatchDTO> {

    private final Logger log = LoggerFactory.getLogger(DispatchService.class);

    private final DispatchRepository dispatchRepository;

    private final ContainerRepository containerRepository;

    private final DispatchRouteRepository dispatchRouteRepository;

    private final PathRepository pathRepository;

    private final LogisticsRepository logisticsRepository;

    private final ProductInfoRepository productInfoRepository;

    private final ElectronicLockRepository electronicLockRepository;

    private final ElectronicLockMessageRepository electronicLockMessageRepository;

    private final DispatchMapper dispatchMapper;

    private final ElectronicLockMessageMapper electronicLockMessageMapper;

    private final SiteRepository siteRepository;
    private final AreaRepository areaRepository;

    private final WarnInfoRepository warnInfoRepository;

    private final UserInfoService userInfoService;
    private final LanguageRepository languageRepository;
    private final Languagesproperties languagesproperties;

    public DispatchService(DispatchRepository dispatchRepository, DispatchMapper dispatchMapper,
                           ContainerRepository containerRepository, LogisticsRepository logisticsRepository,
                           ProductInfoRepository productInfoRepository, DispatchRouteRepository dispatchRouteRepository,
                           PathRepository pathRepository, ElectronicLockRepository electronicLockRepository,
                           ElectronicLockMessageMapper electronicLockMessageMapper,
                           ElectronicLockMessageRepository electronicLockMessageRepository,
                           SiteRepository siteRepository, AreaRepository areaRepository,
                           WarnInfoRepository warnInfoRepository, UserInfoService userInfoService, LanguageRepository languageRepository, Languagesproperties languagesproperties) {
        this.dispatchRepository = dispatchRepository;
        this.dispatchMapper = dispatchMapper;
        this.containerRepository = containerRepository;
        this.logisticsRepository = logisticsRepository;
        this.productInfoRepository = productInfoRepository;
        this.dispatchRouteRepository = dispatchRouteRepository;
        this.pathRepository = pathRepository;
        this.electronicLockRepository = electronicLockRepository;
        this.electronicLockMessageMapper = electronicLockMessageMapper;
        this.electronicLockMessageRepository = electronicLockMessageRepository;
        this.siteRepository = siteRepository;
        this.areaRepository = areaRepository;
        this.warnInfoRepository = warnInfoRepository;
        this.userInfoService = userInfoService;
        this.languageRepository = languageRepository;
        this.languagesproperties = languagesproperties;
    }

    /**
     * Save a dispatch.
     *
     * @param dispatchDTO the entity to save
     * @return the persisted entity
     */
    public DispatchDTO save(DispatchDTO dispatchDTO) {
        log.debug("Request to save Dispatch : {}", dispatchDTO);
        Dispatch dispatch = dispatchMapper.toEntity(dispatchDTO);
        dispatch = dispatchRepository.save(dispatch);
        return dispatchMapper.toDto(dispatch);
    }

    /**
     * Get all the dispatches.
     *
     * @return the list of entities
     */
    @Transactional(readOnly = true)
    public List<DispatchDTO> findAll() {
        log.debug("Request to get all Dispatches");
        return dispatchRepository.findAll().stream()
                .map(dispatchMapper::toDto)
                .collect(Collectors.toCollection(LinkedList::new));
    }

    public BaseDTO startDispatch(String containerId, DispatchDTO dispatchDTO) {
        //信息检查
        if (containerId == null || "".equals(containerId)) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "container_code_not_null", null);
        }
        Container container = containerRepository.findOne(containerId);
        if (container == null) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "container_info_not_find", null);
        }
        Logistics logistics = logisticsRepository.findFirstByContainerIdAndDeletionTimeIsNullOrderByCreationTimeDesc(containerId);
        if (logistics == null) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "reg_info_no_have_logistics", null);
        }
        ProductInfo productInfo = productInfoRepository.findFirstByContainerIdAndDeletionTimeIsNull(containerId);
        if (productInfo == null) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "reg_info_no_have_cargo", null);
        }
        if (StringUtils.isEmpty(dispatchDTO.getRouteId())) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "not_have_dispatch_route", null);
        }
        // 查看调度路径是否存在
        com.csproj.basic.domain.Path dispatchRoute = pathRepository.findOne(dispatchDTO.getRouteId());
//        DispatchRoute dispatchRoute = dispatchRouteRepository.findOne(dispatchDTO.getRouteId());
        if (dispatchRoute == null) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "dispatch_route_no_exist", null);
        }

        Dispatch dispatch = new Dispatch();
        //设置集装箱信息
        dispatch.setContainerId(container.getId());//集装箱主键
        dispatch.setContainerCode(container.getContainerNo());//集装箱编号
        dispatch.setContainerStatus(ContainerStatus.WAITBLOCK.getIndex() + "");//设置集装箱状态-待施封
        //设置调度路径信息
        dispatch.setRouteId(dispatchDTO.getRouteId());
        dispatch.setRouteCode(dispatchRoute.getPathNo());
        //调度路径的起始、结束站点设置
        dispatch.setLaunchsiteId(dispatchRoute.getStartSiteId());
        dispatch.setDestinationsiteId(dispatchRoute.getEndSiteId());

        dispatch.setTimeLimit(dispatchDTO.getTimeLimit());

        // 设置创建时间、创建人
        dispatch.setCreationTime(ZonedDateTime.now());
        dispatch.setCreatorUserId(SecurityUtils.getCurrentUserId());
        dispatch.setLastModificationTime(ZonedDateTime.now());
//        if (StringUtils.isNotBlank(dispatch.getTimeLimit())) {
//            float min = Float.parseFloat(dispatch.getTimeLimit());
//
//            dispatch.setExpectedarriveTime(dispatch.getCreationTime().plusHours((long) min));
//        }
        dispatch.setLastModifierUserId(SecurityUtils.getCurrentUserId());
        dispatch = dispatchRepository.save(dispatch);
        dispatchDTO = dispatchMapper.toDto(dispatch);
        extendDestinationsiteName(dispatchDTO);
        extendLaunchsiteName(dispatchDTO);

        //更新集装箱信息
        container.setDptFlag(true);//设置开启调度
        container = containerRepository.save(container);

        return BaseDTO.createBaseDTO(dispatchDTO).setMessage("dispatch_begin");
    }

    @Transactional(readOnly = true)
    public BaseDTO searchAllDispatchPage(Integer page, Integer limit, Map<String, Object> option) {
        return searchAllDispatchPageCommon(page, limit, option);
    }

    @Transactional(readOnly = true)
    public List<DispatchDTO> searchAllDispatchExport(Map<String, Object> option) {
        Specification<Dispatch> dispatchSpecification = null;
        if (option != null && !option.isEmpty()) {
            dispatchSpecification = new Specification<Dispatch>() {
                @Override
                public Predicate toPredicate(Root<Dispatch> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                    //设置查询条件
                    List<Predicate> list = new ArrayList<Predicate>();
                    for (Map.Entry<String, Object> km : option.entrySet()) {
                        String key = km.getKey();
                        Object val = km.getValue();
                        if ("containerCode".equals(key)) {//集装箱编号
                            if (val == null || val.toString().equals("")) {
                                continue;
                            }
                            Predicate p = criteriaBuilder.like(root.get("containerCode").as(String.class), "%" + km.getValue().toString() + "%");
                            list.add(p);
                        } else if ("launchsiteId".equals(key)) {//启运站点
                            if (val == null || val.toString().equals("")) {
                                continue;
                            }
                            Predicate p = criteriaBuilder.equal(root.get("launchsiteId").as(String.class), km.getValue());
                            list.add(p);
                        } else if ("destinationsiteId".equals(key)) {//目的站点
                            if (val == null || val.toString().equals("")) {
                                continue;
                            }
                            Predicate p = criteriaBuilder.equal(root.get("destinationsiteId").as(String.class), km.getValue());
                            list.add(p);
                        } else if ("containerStatus".equals(key)) {//集装箱状态
                            if (val == null || ((List<Integer>) val).isEmpty()) {
                                continue;
                            }
                            Path<Object> path = root.get("containerStatus");
                            CriteriaBuilder.In<Object> in = criteriaBuilder.in(path);
                            List<Integer> value = (List<Integer>) km.getValue();
                            for (Integer v : value) {
                                in.value(v + "");
                            }
                            Predicate p = criteriaBuilder.and(in);
                            list.add(p);
                        } else if ("arrived".equals(key)) {
//                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

                            ZonedDateTime now = ZonedDateTime.now();
                            Predicate p = criteriaBuilder.greaterThan(root.get("expectedarriveTime").as(ZonedDateTime.class),
                                    now.truncatedTo(ChronoUnit.DAYS));
                            list.add(p);


                            Predicate p1 = criteriaBuilder.lessThan(root.get("expectedarriveTime").as(ZonedDateTime.class),
                                    now.plusDays(1).truncatedTo(ChronoUnit.DAYS));
                            list.add(p1);

                        }
                    }

                    if((!option.containsKey("launchsiteId") || option.get("launchsiteId").equals(""))
                            && (!option.containsKey("destinationsiteId") || option.get("destinationsiteId").equals(""))){
                        //如果没有站点 取默认(站点管理员的站点)

                        String siteid = userInfoService.getCurrentUserSiteId();
                        if(siteid!=null && !"nositeID".equals(siteid)){
                            Predicate ps = criteriaBuilder.equal(root.get("launchsiteId").as(String.class), siteid);
                            Predicate pd = criteriaBuilder.equal(root.get("destinationsiteId").as(String.class), siteid);
                            Predicate p = criteriaBuilder.or(ps, pd);
                            list.add(p);
                        }

                    }
                    //未删除
                    Predicate p1 = criteriaBuilder.isNull(root.get("deletionTime").as(ZonedDateTime.class));
                    list.add(p1);
//                    //站点管理员
//                    String siteId = userInfoService.getCurrentUserSiteId();
//
//                    if(!StringUtils.isEmpty(siteId) && !siteId.equals("")&&!siteId.equals("nositeID")){
//                        Predicate ps = criteriaBuilder.equal(root.get("launchsiteId"), siteId);
//
//                        Predicate p4 = criteriaBuilder.equal(root.get("destinationsiteId"), siteId);
//                        Predicate p5= criteriaBuilder.or(ps, p4);
//                        list.add(p5);
//
//                    }
                    //已经开启调度的集装箱
                    Subquery subQuery = criteriaQuery.subquery(String.class);
                    Root fromUR = subQuery.from(Container.class);
                    subQuery.select(fromUR.get("id")).where(criteriaBuilder.and(criteriaBuilder.isNotNull(fromUR.get("dptFlag")),
                            criteriaBuilder.isTrue(fromUR.get("dptFlag"))));
                    Predicate p2 = criteriaBuilder.in(root.get("containerId")).value(subQuery);
                    list.add(p2);

                    return criteriaBuilder.and(list.toArray(new Predicate[0]));
                }
            };
        } else {
            dispatchSpecification = new Specification<Dispatch>() {
                @Override
                public Predicate toPredicate(Root<Dispatch> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                    //设置查询条件
                    List<Predicate> list = new ArrayList<Predicate>();
                    //如果没有站点 取默认(站点管理员的站点)

                    String siteid = userInfoService.getCurrentUserSiteId();
                    if(siteid!=null && !"nositeID".equals(siteid)){
                        Predicate ps = criteriaBuilder.equal(root.get("launchsiteId").as(String.class), siteid);
                        Predicate pd = criteriaBuilder.equal(root.get("destinationsiteId").as(String.class), siteid);
                        Predicate p = criteriaBuilder.or(ps, pd);
                        list.add(p);
                    }
                    //未删除
                    Predicate p1 = criteriaBuilder.isNull(root.get("deletionTime").as(ZonedDateTime.class));
                    list.add(p1);
                    //站点管理员
//                    String siteId = userInfoService.getCurrentUserSiteId();
//
//                    if(!StringUtils.isEmpty(siteId) && !siteId.equals("")&&!siteId.equals("nositeID")){
//                        Predicate ps = criteriaBuilder.equal(root.get("launchsiteId"), siteId);
//
//                        Predicate p4 = criteriaBuilder.equal(root.get("destinationsiteId"), siteId);
//                        Predicate p5= criteriaBuilder.or(ps, p4);
//                        list.add(p5);
//
//                    }
                    //已经开启调度的集装箱
                    Subquery subQuery = criteriaQuery.subquery(String.class);
                    Root fromUR = subQuery.from(Container.class);
                    subQuery.select(fromUR.get("id")).where(criteriaBuilder.and(criteriaBuilder.isNotNull(fromUR.get("dptFlag")),
                            criteriaBuilder.isTrue(fromUR.get("dptFlag"))));
                    Predicate p2 = criteriaBuilder.in(root.get("containerId")).value(subQuery);
                    list.add(p2);
                    return criteriaBuilder.and(list.toArray(new Predicate[0]));
                }
            };
        }
        //调用业务层，返回Page
        List<Dispatch> dispatches = dispatchRepository.findAll(dispatchSpecification);
        System.out.println(System.currentTimeMillis());
        List<DispatchDTO> dispatchDTOS = dispatches.stream().
                map(n -> {
                    DispatchDTO dispatchDTO = dispatchMapper.toDto(n);
                    extendLaunchsiteName(dispatchDTO);
                    extendDestinationsiteName(dispatchDTO);
                    //      extendHasWarn(dispatchDTO);
                    return dispatchDTO;
                }).collect(Collectors.toList());
        this.setHasWarn(dispatchDTOS);
        this.extendContainerStatusName(dispatchDTOS);

        System.out.println(System.currentTimeMillis());
        return dispatchDTOS;
    }


    private void extendContainerStatusName(List<DispatchDTO> dispatches) {

        Map<String, Object> currentMp = new HashMap<String, Object>() {
        };
        List<Language> l = languageRepository.findByDefault();
        Language first = null;
        if (l.size() > 0) {
            first = l.get(0);
        }

        if (first != null) {
            if (first.getName().equals("zh")) {
                currentMp = languagesproperties.getZh();
            } else if (first.getName().equals("en")) {
                currentMp = languagesproperties.getEn();

            } else if (first.getName().equals("pu")) {
                currentMp = languagesproperties.getPu();
            }
        }
        for (DispatchDTO dispatch : dispatches) {
            String name = ContainerStatus.getName(Integer.valueOf(dispatch.getContainerStatus()));
            dispatch.setContainerStatusName(currentMp.get(name).toString());
        }
    }


    private void setHasWarn(List<DispatchDTO> dispatches) {
        List<String> ids = dispatches.stream().map(n -> n.getId()).collect(Collectors.toList());
        if (ids != null && !ids.isEmpty()) {
            List<WarnInfo> warnInfos = warnInfoRepository.findAllByDispatchId(ids);
            dispatches.forEach(dispatch -> {
                        WarnInfo warnInfo = warnInfos.stream().filter(w -> w.getDispatchId().equals(dispatch.getId())).findFirst().orElse(null);
                        if (warnInfo == null) {
                            dispatch.setHasWarn(false);
                        } else {
                            dispatch.setHasWarn(true);
                        }
                    }
            );
        }
    }

    public BaseDTO searchAllDispatchPageCommon(Integer page, Integer limit, Map<String, Object> option) {
        System.out.println(System.currentTimeMillis());
        Pageable pageable = PageableTools.basicPage(page, limit, new SortDto("desc", "creationTime"));
        Specification<Dispatch> dispatchSpecification = null;
        if (option != null && !option.isEmpty()) {
            dispatchSpecification = new Specification<Dispatch>() {
                @Override
                public Predicate toPredicate(Root<Dispatch> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                    //设置查询条件
                    List<Predicate> list = new ArrayList<Predicate>();
                    for (Map.Entry<String, Object> km : option.entrySet()) {
                        String key = km.getKey();
                        Object val = km.getValue();
                        if ("containerCode".equals(key)) {//集装箱编号
                            if (val == null || val.toString().equals("")) {
                                continue;
                            }
                            Predicate p = criteriaBuilder.like(root.get("containerCode").as(String.class), "%" + km.getValue().toString() + "%");
                            list.add(p);
                        } else if ("launchsiteId".equals(key)) {//启运站点
                            if (val == null || val.toString().equals("")) {
                                continue;
                            }
                            Predicate p = criteriaBuilder.equal(root.get("launchsiteId").as(String.class), km.getValue());
                            list.add(p);
                        } else if ("destinationsiteId".equals(key)) {//目的站点
                            if (val == null || val.toString().equals("")) {
                                continue;
                            }
                            Predicate p = criteriaBuilder.equal(root.get("destinationsiteId").as(String.class), km.getValue());
                            list.add(p);
                        } else if ("containerStatus".equals(key)) {//集装箱状态
                            if (val == null || ((List<Integer>) val).isEmpty()) {
                                continue;
                            }
                            Path<Object> path = root.get("containerStatus");
                            CriteriaBuilder.In<Object> in = criteriaBuilder.in(path);
                            List<Integer> value = (List<Integer>) km.getValue();
                            for (Integer v : value) {
                                in.value(v + "");
                            }
                            Predicate p = criteriaBuilder.and(in);
                            list.add(p);
                        } else if ("arrived".equals(key)) {
//                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

                            ZonedDateTime now = ZonedDateTime.now();
                            Predicate p = criteriaBuilder.greaterThan(root.get("expectedarriveTime").as(ZonedDateTime.class),
                                    now.truncatedTo(ChronoUnit.DAYS));
                            list.add(p);


                            Predicate p1 = criteriaBuilder.lessThan(root.get("expectedarriveTime").as(ZonedDateTime.class),
                                    now.plusDays(1).truncatedTo(ChronoUnit.DAYS));
                            list.add(p1);

                        }
                    }

                    if((!option.containsKey("launchsiteId") || option.get("launchsiteId").equals(""))
                            && (!option.containsKey("destinationsiteId") || option.get("destinationsiteId").equals(""))){
                        //如果没有站点 取默认(站点管理员的站点)

                        String siteid = userInfoService.getCurrentUserSiteId();
                        if(siteid!=null && !"nositeID".equals(siteid)){
                            Predicate ps = criteriaBuilder.equal(root.get("launchsiteId").as(String.class), siteid);
                            Predicate pd = criteriaBuilder.equal(root.get("destinationsiteId").as(String.class), siteid);
                            Predicate p = criteriaBuilder.or(ps, pd);
                            list.add(p);
                        }

                    }
                    //未删除
                    Predicate p1 = criteriaBuilder.isNull(root.get("deletionTime").as(ZonedDateTime.class));
                    list.add(p1);
//                    //站点管理员
//                    String siteId = userInfoService.getCurrentUserSiteId();
//                    if(!StringUtils.isEmpty(siteId) && !siteId.equals("")&&!siteId.equals("nositeID")){
//                        Predicate ps = criteriaBuilder.equal(root.get("launchsiteId"), siteId);
//
//                        Predicate p4 = criteriaBuilder.equal(root.get("destinationsiteId"), siteId);
//                        Predicate p5= criteriaBuilder.or(ps, p4);
//                        list.add(p5);
//
//                    }
                    //已经开启调度的集装箱
                    Subquery subQuery = criteriaQuery.subquery(String.class);
                    Root fromUR = subQuery.from(Container.class);
                    subQuery.select(fromUR.get("id")).where(criteriaBuilder.and(criteriaBuilder.isNotNull(fromUR.get("dptFlag")),
                            criteriaBuilder.isTrue(fromUR.get("dptFlag"))));
                    Predicate p2 = criteriaBuilder.in(root.get("containerId")).value(subQuery);
                    list.add(p2);

                    return criteriaBuilder.and(list.toArray(new Predicate[0]));
                }
            };
        } else {
            dispatchSpecification = new Specification<Dispatch>() {
                @Override
                public Predicate toPredicate(Root<Dispatch> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                    //设置查询条件
                    List<Predicate> list = new ArrayList<Predicate>();

                    //如果没有站点 取默认(站点管理员的站点)

                    String siteid = userInfoService.getCurrentUserSiteId();
                    if(siteid!=null && !"nositeID".equals(siteid)){
                        Predicate ps = criteriaBuilder.equal(root.get("launchsiteId").as(String.class), siteid);
                        Predicate pd = criteriaBuilder.equal(root.get("destinationsiteId").as(String.class), siteid);
                        Predicate p = criteriaBuilder.or(ps, pd);
                        list.add(p);
                    }


                    //未删除
                    Predicate p1 = criteriaBuilder.isNull(root.get("deletionTime").as(ZonedDateTime.class));
                    list.add(p1);
//                    //站点管理员
//                    String siteId = userInfoService.getCurrentUserSiteId();
//
//                    if(!StringUtils.isEmpty(siteId) && !siteId.equals("")&&!siteId.equals("nositeID")){
//                        Predicate ps = criteriaBuilder.equal(root.get("launchsiteId"), siteId);
//
//                        Predicate p4 = criteriaBuilder.equal(root.get("destinationsiteId"), siteId);
//                        Predicate p5= criteriaBuilder.or(ps, p4);
//                        list.add(p5);
//
//                    }
                    //已经开启调度的集装箱
                    Subquery subQuery = criteriaQuery.subquery(String.class);
                    Root fromUR = subQuery.from(Container.class);
                    subQuery.select(fromUR.get("id")).where(criteriaBuilder.and(criteriaBuilder.isNotNull(fromUR.get("dptFlag")),
                            criteriaBuilder.isTrue(fromUR.get("dptFlag"))));
                    Predicate p2 = criteriaBuilder.in(root.get("containerId")).value(subQuery);
                    list.add(p2);
                    return criteriaBuilder.and(list.toArray(new Predicate[0]));
                }
            };
        }
        //调用业务层，返回Page
        Page<Dispatch> dispatches = dispatchRepository.findAll(dispatchSpecification, pageable);
        System.out.println(System.currentTimeMillis());
        List<DispatchDTO> dispatchDTOS = dispatches.getContent().stream().
                map(n -> {
                    DispatchDTO dispatchDTO = dispatchMapper.toDto(n);
                    extendLaunchsiteName(dispatchDTO);
                    extendDestinationsiteName(dispatchDTO);

                    //      extendHasWarn(dispatchDTO);
                    return dispatchDTO;
                }).collect(Collectors.toList());
        this.setHasWarn(dispatchDTOS);
        this.extendContainerStatusName(dispatchDTOS);
        System.out.println(System.currentTimeMillis());
        return BaseDTO.createBaseDTO(dispatches).setFieldList(dispatchDTOS);
    }


    public BaseDTO searchRoutesByCond(DispatchRouteParam dispatchRouteParam) {
        if (dispatchRouteParam == null) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "filter_params_null", null);
        }
        System.out.println(dispatchRouteParam.getPageParam());
        Pageable pageable = PageableTools.basicPage(dispatchRouteParam.getPageParam().getPage(),
                dispatchRouteParam.getPageParam().getLimit(),
                new SortDto("asc", "id"));
        Specification<ElectronicLockMessage> dispatchSpecification = null;
        dispatchSpecification = new Specification<ElectronicLockMessage>() {
            @Override
            public Predicate toPredicate(Root<ElectronicLockMessage> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                //设置查询条件
                List<Predicate> list = new ArrayList<Predicate>();
                /*********过滤信息start***********/
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                if (dispatchRouteParam.getStartTime() != null) {//起始时间
                    Predicate p = criteriaBuilder.greaterThan(root.get("time").as(ZonedDateTime.class),
                            dispatchRouteParam.getStartTime());
                    list.add(p);
                }
                if (dispatchRouteParam.getEndTime() != null) {//结束时间
                    Predicate p = criteriaBuilder.lessThan(root.get("time").as(ZonedDateTime.class),
                            dispatchRouteParam.getEndTime());
                    list.add(p);
                }
                if (!StringUtils.isEmpty(dispatchRouteParam.getLockId())) {//关锁编号
                    Predicate p = criteriaBuilder.equal(root.get("elNumber").as(String.class), dispatchRouteParam.getLockId());
                    list.add(p);
                }
                /*********过滤信息end***********/

                Subquery subQuery = criteriaQuery.subquery(String.class);
                Root fromUR = subQuery.from(Dispatch.class);
                /*********子查询-调度表-过滤***********/
                List<Predicate> andcb = new ArrayList<Predicate>();
//                Predicate pc = criteriaBuilder.equal(fromUR.get("containerStatus").as(String.class), "3");//在途
//                andcb.add(pc);
                Predicate pd = criteriaBuilder.isNull(fromUR.get("deletionTime").as(ZonedDateTime.class));//未删除
                andcb.add(pd);
                if (!StringUtils.isEmpty(dispatchRouteParam.getSiteid())) {//启运站点
                    Predicate p = criteriaBuilder.equal(fromUR.get("launchsiteId").as(String.class), dispatchRouteParam.getSiteid());
                    Predicate p1 = criteriaBuilder.equal(fromUR.get("destinationsiteId").as(String.class), dispatchRouteParam.getSiteid());

                    Predicate p5 = criteriaBuilder.or(p, p1);
                    andcb.add(p5);
                }

                if (!StringUtils.isEmpty(dispatchRouteParam.getLockId())) {//关锁编号
                    Predicate p = criteriaBuilder.equal(fromUR.get("lockCode").as(String.class), dispatchRouteParam.getLockId());
                    andcb.add(p);
                }
                /*********子查询-调度表-过滤***********/
                subQuery.select(fromUR.get("id")).where(criteriaBuilder.and(andcb.toArray(new Predicate[0])));
                Predicate p2 = criteriaBuilder.in(root.get("dispatchId")).value(subQuery);
                list.add(p2);
                return criteriaBuilder.and(list.toArray(new Predicate[0]));
            }
        };


        //调用业务层，返回Page
        Page<ElectronicLockMessage> electronicLockMessages = electronicLockMessageRepository.findAll(dispatchSpecification, pageable);

        List<ElectronicLockMessageDTO> electronicLockMessageDTOS = electronicLockMessages.getContent().stream().
                map(n -> {
                    ElectronicLockMessageDTO electronicLockMessageDTO = electronicLockMessageMapper.toDto(n);
                    return electronicLockMessageDTO;
                }).collect(Collectors.toList());
        return BaseDTO.createBaseDTO(electronicLockMessages).setFieldList(electronicLockMessageDTOS);
    }


    /**
     * 箱锁绑定
     *
     * @param containerCode
     * @param lockCode
     * @param platenumber
     * @return
     */
    public BaseDTO bindContainerWithLock(String containerCode, String lockCode, String platenumber,
                                         String handsetCode, Double postionLng, Double postionLat) {
        if (StringUtils.isEmpty(containerCode)) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "container_code_no_have", null).setSuccess(false);
        }
        if (StringUtils.isEmpty(lockCode)) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "lock_code_no_have", null).setSuccess(false);
        }

        Dispatch exist = dispatchRepository.findFirstByContainerCodeAndContainerStatusAndDeletionTimeIsNullOrderByCreationTime(
                containerCode, "3");


        if (exist != null) {
            return BaseDTO.createBaseDTO(dispatchMapper.toDto(exist)).setSuccess(true);
        }

        Dispatch existLock = dispatchRepository.findFirstByLockCodeAndContainerStatusAndDeletionTimeIsNullOrderByCreationTime(
                lockCode, "3");

        if (existLock != null) {
            return BaseDTO.createBaseDTO(dispatchMapper.toDto(exist)).setSuccess(true);
        }

        // 根据集装箱编号查找调度
        Dispatch dispatch = dispatchRepository.findFirstByContainerCodeAndContainerStatusAndDeletionTimeIsNullOrderByCreationTime(
                containerCode, "1");
        ElectronicLock electronicLock = electronicLockRepository.findFirstByLockNoAndEnableFlagTrueAndDeletionTimeIsNull(lockCode);
        if (electronicLock == null) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "not_find_lock_set", null).setSuccess(false);
        }

        // 修改调度信息
        if (dispatch != null) {

            //验证施封范围
            com.csproj.basic.domain.Path path = pathRepository.findOne(dispatch.getRouteId());

            Site site = siteRepository.findOne(dispatch.getLaunchsiteId());
            if (site == null)
                return new BaseDTO(BaseDTO.CODE_PARAM, "path_no_have_start_and_end_site", null).setSuccess(false);
            if (path != null) {


                Area area = new Area();
                if (StringUtils.isNotBlank(path.getStartWarehouseId())) {
                    area = areaRepository.findFirstByWarehouseIdAndSiteIdAndDeletedFlagIsFalseAndBlockFlagIsTrue(path.getStartWarehouseId(), path.getStartSiteId());
                } else {
                    area = areaRepository.findFirstByWarehouseIdAndSiteIdAndDeletedFlagIsFalseAndBlockFlagIsTrue(null, path.getStartSiteId());

                }

                if (area != null) {
                    if (!PointSurface.isInCircle(postionLat, postionLng, area.getLatitude().doubleValue(),
                            area.getLongitude().doubleValue(), area.getRadius().toString())) {
                        return new BaseDTO(BaseDTO.CODE_PARAM, "exceed_lock_range", null).setSuccess(false);
                    }
                } else {
                    return new BaseDTO(BaseDTO.CODE_PARAM, "area_can_not_found", null).setSuccess(false);
                }
            } else {
                return new BaseDTO(BaseDTO.CODE_PARAM, "path_can_not_found", null).setSuccess(false);
            }

            dispatch.setLockCode(lockCode);//关锁编号
            if (!StringUtils.isEmpty(platenumber)) {
                dispatch.setPlatenumber(platenumber);//车牌号
            }
            dispatch.setContainerStatus("3");
            dispatch.setContainerCode(containerCode);
            dispatch.setHandsetCode(handsetCode);
            dispatch.setLaunchTime(ZonedDateTime.now());
            if (StringUtils.isNotBlank(dispatch.getTimeLimit())) {
                float hour = Float.parseFloat(dispatch.getTimeLimit());
                dispatch.setExpectedarriveTime(dispatch.getLaunchTime().plusMinutes((long) (hour * 60)));
            }
            dispatch.setLastModificationTime(ZonedDateTime.now());
            dispatch.setLastModifierUserId(SecurityUtils.getCurrentUserId());
            dispatch = dispatchRepository.save(dispatch);
            //修改锁状态

            electronicLock.setState("1");
            electronicLock.setNowSiteId(dispatch.getDestinationsiteId());
            electronicLockRepository.save(electronicLock);

            return BaseDTO.createBaseDTO(dispatchMapper.toDto(dispatch)).setSuccess(true);
        }
        return new BaseDTO(BaseDTO.CODE_PARAM, "no_exist_dispatch_info", null).setSuccess(false);
    }

    public BaseDTO searchHistoryByCompany(String startCompanyId, String endCompanyId) {
        if (StringUtils.isBlank(startCompanyId)) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "not_find_start_site", null);
        }
        if (StringUtils.isBlank(endCompanyId)) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "not_find_end_site", null);
        }
        List<DispatchDTO> dispatchDTOS = dispatchRepository.findAllByPath(startCompanyId, endCompanyId).
                stream().map(n -> {
            DispatchDTO dispatchDTO = dispatchMapper.toDto(n);
            return dispatchDTO;

        }).collect(Collectors.toList());

        return BaseDTO.createBaseDTO(dispatchDTOS);
    }

    public BaseDTO searchHistoryBySiteOrCompany(String startSiteId, String endSiteId, String startCompanyId, String endCompanyId) {
        if (StringUtils.isBlank(startSiteId)) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "not_find_start_site", null).setSuccess(false);
        }
        if (StringUtils.isBlank(endSiteId)) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "not_find_end_site", null).setSuccess(false);
        }
        List<DispatchDTO> dispatchDTOS = null;
        if (StringUtils.isNotBlank(startCompanyId) && StringUtils.isNotBlank(endCompanyId)) {
            dispatchDTOS = dispatchRepository.findAllByPath(startCompanyId, endCompanyId).
                    stream().map(n -> {
                DispatchDTO dispatchDTO = dispatchMapper.toDto(n);
                return dispatchDTO;
            }).collect(Collectors.toList());
        } else if (!StringUtils.isNotBlank(startCompanyId) && !StringUtils.isNotBlank(endCompanyId)) {
            dispatchDTOS = dispatchRepository.findAllByPathAndSite(startSiteId, endSiteId).
                    stream().map(n -> {
                DispatchDTO dispatchDTO = dispatchMapper.toDto(n);
                return dispatchDTO;
            }).collect(Collectors.toList());
        } else if (!StringUtils.isNotBlank(startCompanyId) && StringUtils.isNotBlank(endCompanyId)) {
            dispatchDTOS = dispatchRepository.findAllByPathAndSiteNoStartCompany(startSiteId, endSiteId, endCompanyId).
                    stream().map(n -> {
                DispatchDTO dispatchDTO = dispatchMapper.toDto(n);
                return dispatchDTO;
            }).collect(Collectors.toList());
        } else if (!StringUtils.isNotBlank(endCompanyId) && StringUtils.isNotBlank(startCompanyId)) {
            dispatchDTOS = dispatchRepository.findAllByPathAndSiteNoEndCompany(startSiteId, endSiteId, startCompanyId).
                    stream().map(n -> {
                DispatchDTO dispatchDTO = dispatchMapper.toDto(n);
                return dispatchDTO;
            }).collect(Collectors.toList());
        }
        return BaseDTO.createBaseDTO(dispatchDTOS);
    }

    public BaseDTO searchHistoryPoisitionById(String dispatchId) {
        if (StringUtils.isBlank(dispatchId)) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "dispatch_info_no_upload", null);
        }
        Dispatch dispatch = dispatchRepository.findOne(dispatchId);
        if (dispatch == null) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "dispatch_info_not_exist", null);
        }

        //获取启运-到达时间
        HistoryPosition historyPosition = new HistoryPosition();
        historyPosition.setLaunchTime(dispatch.getLaunchTime());
        historyPosition.setArriveTime(dispatch.getArriveTime());

        //获取调度历史路径信息
        List<HistoryPositionDetail> historyPositionDetails = electronicLockMessageRepository.findAllByDispatchIdOrderByTimeAsc(dispatchId).
                stream().map(n -> {
            HistoryPositionDetail historyPositionDetail = new HistoryPositionDetail();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            historyPositionDetail.setUpTime(n.getTime().format(formatter));
            historyPositionDetail.setLatitude(n.getLatitude());
            historyPositionDetail.setLongitude(n.getLongitude());
            return historyPositionDetail;

        }).collect(Collectors.toList());
        historyPosition.setHistoryPositionDetails(new LinkedList<>(historyPositionDetails));

        return BaseDTO.createBaseDTO(historyPosition);
    }

    public BaseDTO searchDispatchByContainerId(String containerId) {
        if (StringUtils.isEmpty(containerId)) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "container_code_no_have", null);
        }
        Dispatch dispatch = dispatchRepository.findFirstByContainerCodeAndArriveTimeIsNullAndDeletionTimeIsNullOrderByCreationTime(containerId);
        DispatchDTO dispatchDTO = dispatchMapper.toDto(dispatch);
        extendLaunchsiteName(dispatchDTO);
        extendDestinationsiteName(dispatchDTO);
        extendHasWarn(dispatchDTO);

        return BaseDTO.createBaseDTO(dispatchDTO);
    }

    public BaseDTO searchDispatchByLockNo(String lockNo) {
        if (StringUtils.isEmpty(lockNo)) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "lock_code_not_null", null);
        }
        Dispatch dispatch = dispatchRepository.findFirstByLockCodeAndDeletionTimeIsNullAndArriveTimeIsNullOrderByCreationTimeDesc(lockNo);
        DispatchDTO dispatchDTO = dispatchMapper.toDto(dispatch);
        extendLaunchsiteName(dispatchDTO);
        extendDestinationsiteName(dispatchDTO);
        extendHasWarn(dispatchDTO);

        return BaseDTO.createBaseDTO(dispatchDTO);
    }

    public BaseDTO unBlock(String containerCode, String lockCode, Double postionLng, Double postionLat) {
        if (StringUtils.isEmpty(containerCode)) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "container_code_no_have", null).setSuccess(false);
        }
        if (StringUtils.isEmpty(lockCode)) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "lock_code_no_have", null).setSuccess(false);
        }
        ElectronicLock electronicLock = electronicLockRepository.findFirstByLockNoAndEnableFlagTrueAndDeletionTimeIsNull(lockCode);
        if (electronicLock == null) {
            return new BaseDTO(BaseDTO.CODE_PARAM, "not_find_lock_set", null).setSuccess(false);
        }
        // 根据集装箱编号查找调度
        Dispatch dispatch = dispatchRepository.findFirstByContainerCodeAndContainerStatusAndDeletionTimeIsNullOrderByCreationTime(
                containerCode, "3");
        // 修改调度信息
        if (dispatch != null) {
            //验证施封范围
            com.csproj.basic.domain.Path path = pathRepository.getOne(dispatch.getRouteId());

            Site site = siteRepository.findOne(dispatch.getDestinationsiteId());
            if (site == null)
                return new BaseDTO(BaseDTO.CODE_PARAM, "path_no_end_site", null).setSuccess(false);

            if (path != null) {
                Area area = new Area();
                if (StringUtils.isNotBlank(path.getEndWarehouseId()))
                    area = areaRepository.findFirstByWarehouseIdAndSiteIdAndDeletedFlagIsFalseAndUnblockFlagIsTrue(path.getEndWarehouseId(), path.getEndSiteId());
                else
                    area = areaRepository.findFirstByWarehouseIdAndSiteIdAndDeletedFlagIsFalseAndUnblockFlagIsTrue(null, path.getEndSiteId());

                if (area != null) {
                    log.info("postionLat：" + postionLat.toString() + "postionLng：" + postionLng + "lat:" + area.getLatitude() + "lng:" + area.getLongitude() + "radius:" + area.getRadius());
                    if (!PointSurface.isInCircle(postionLat, postionLng, area.getLatitude().doubleValue(),
                            area.getLongitude().doubleValue(), area.getRadius().toString())) {
                        return new BaseDTO(BaseDTO.CODE_PARAM, "exceed_unlock_range", null).setSuccess(false);
                    }
                } else {
                    return new BaseDTO(BaseDTO.CODE_PARAM, "area_can_not_found", null).setSuccess(false);
                }
            } else {
                return new BaseDTO(BaseDTO.CODE_PARAM, "path_can_not_found", null).setSuccess(false);
            }

            dispatch.setContainerStatus("5");
            dispatch.setArriveTime(ZonedDateTime.now());
            dispatch.setLastModificationTime(ZonedDateTime.now());
            dispatch.setLastModifierUserId(SecurityUtils.getCurrentUserId());
            dispatch = dispatchRepository.save(dispatch);
            //设置锁状态

            electronicLock.setState("2");
            electronicLock.setNowSiteId(dispatch.getDestinationsiteId());
            electronicLockRepository.save(electronicLock);


            return BaseDTO.createBaseDTO(dispatchMapper.toDto(dispatch)).setMessage("lockset_unlock").setSuccess(true);
        }
        return new BaseDTO(BaseDTO.CODE_PARAM, "no_exist_dispatch_info", null).setSuccess(false);
    }

    public BaseDTO searchDispatchOfUnBind() {
        List<Dispatch> dispatches = dispatchRepository.findAllOfUnBind();
        System.out.println(dispatches.size());
        List<DispatchDTO> dispatchDTOS = dispatches.stream().map(n -> {
            DispatchDTO dispatchDTO = dispatchMapper.toDto(n);
            return dispatchDTO;
        }).collect(Collectors.toList());


        return BaseDTO.createBaseDTO(dispatchDTOS);
    }

    public BaseDTO searchDispatchOfBind(String lockCode) {
        List<Dispatch> dispatches = dispatchRepository.findAllOfBind(lockCode);
        System.out.println(dispatches.size());
        List<DispatchDTO> dispatchDTOS = dispatches.stream().map(n -> {
            DispatchDTO dispatchDTO = dispatchMapper.toDto(n);
            return dispatchDTO;
        }).collect(Collectors.toList());


        return BaseDTO.createBaseDTO(dispatchDTOS);
    }

    /**
     * 获得当天零时零分零秒
     *
     * @return
     */
    public Date initDateByDay() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }

    public BaseDTO searchRouterAvgTime(String routerId) {
        ZonedDateTime nowtime = ZonedDateTime.now();
        ZonedDateTime oldtime = nowtime.plusMonths(-1);

        List<Dispatch> dispatches = dispatchRepository.findAllByRouteIdAndContainerStatusAndArriveTimeIsNotNullAndLaunchTimeIsNotNullAndLaunchTimeLessThanAndArriveTimeGreaterThan(
                routerId, "5", nowtime, oldtime);
        List<DispatchDTO> dispatchDTOS = dispatches.stream().map(n -> {
            DispatchDTO dispatchDTO = dispatchMapper.toDto(n);
            return dispatchDTO;
        }).collect(Collectors.toList());
        return BaseDTO.createBaseDTO().setFieldList(dispatchDTOS);
    }

}
